/* //device/system/broncho-ril/reference-ril.c
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/

#include <telephony/ril.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <alloca.h>
#include "atchannel.h"
#include "at_tok.h"
#include <getopt.h>
#include "broncho-ril.h"
#include "ril_util.h"
#include "ril-sim.h"
#include "ruim_ef_codec.h"

#define LOG_TAG "RIL"
#include "broncho_log.h"

#define EF_ADN_RECORD_SIZE	28
#define EF_SMS_RECORD_SIZE  255

/**
 * Get the current card status.
 *
 * This must be freed using freeCardStatus.
 * @return: On success returns RIL_E_SUCCESS
 */
static int getCardStatus(RIL* thiz, RIL_CardStatus_v5 **pp_card_status) {
    static RIL_AppStatus app_status_array[] = {
        // SIM_ABSENT = 0
        { RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
        // SIM_NOT_READY = 1
        { RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
        // SIM_READY = 2
        { RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
          NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN },
        // SIM_PIN = 3
        { RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
          NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN },
        // SIM_PUK = 4
        { RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
          NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN },
		// SIM PIN2 = 5
		{ RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
		  NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_ENABLED_NOT_VERIFIED},
		// SIM PUK2 = 6
		{ RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
		  NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_ENABLED_BLOCKED},
    };
    RIL_CardState card_state;
    int num_apps;

    int sim_status = RIL_getSIMStatus(thiz);
    if (sim_status == RIL_SIM_ABSENT) {
        card_state = RIL_CARDSTATE_ABSENT;
        num_apps = 0;
    } else {
        card_state = RIL_CARDSTATE_PRESENT;
        num_apps = 1;
    }

    // Allocate and initialize base card status.
    RIL_CardStatus_v5 *p_card_status = malloc(sizeof(RIL_CardStatus_v5));
    p_card_status->card_state = card_state;
    p_card_status->universal_pin_state = RIL_PINSTATE_UNKNOWN;
    p_card_status->gsm_umts_subscription_app_index = RIL_CARD_MAX_APPS;
    p_card_status->cdma_subscription_app_index = RIL_CARD_MAX_APPS;
    p_card_status->num_applications = num_apps;

    // Initialize application status
    int i;
    for (i = 0; i < RIL_CARD_MAX_APPS; i++) {
        p_card_status->applications[i] = app_status_array[RIL_SIM_ABSENT];
    }

    // Pickup the appropriate application status
    // that reflects sim_status for gsm.
    if (num_apps != 0) {
        // Only support one app, gsm
        p_card_status->num_applications = 1;
        p_card_status->cdma_subscription_app_index = 0;

        // Get the correct app status
        p_card_status->applications[0] = app_status_array[sim_status];
    }

    *pp_card_status = p_card_status;
    return RIL_E_SUCCESS;
}

static void freeCardStatus(RIL_CardStatus_v5* pCardStatus)
{
	if(pCardStatus != NULL)
	{
		free(pCardStatus);
	}

	return;
}

static void requestGetSimState(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
	RIL_CardStatus_v5 *p_card_status = NULL;
	int result = 0;

	if ((result = getCardStatus(thiz, &p_card_status)) == RIL_E_SUCCESS)
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, (char*)p_card_status, sizeof(RIL_CardStatus_v5));
	}
	else
	{
		RIL_onRequestComplete(thiz, t, result, NULL, 0);
	}
	freeCardStatus(p_card_status);

	return;
}

static int ef_dialling_numbers_get_response(RIL* thiz,
		RIL_SIM_IO_v5* io_args, RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;
	char resp_data[16];
	char cmd[32];
	ATResponse* p_resp = NULL;
	
	snprintf(cmd, 32, "AT+CPBS=\"SM\"");
	ril_command_exec_for_result(thiz, cmd);
	snprintf(cmd, 32, "AT+CPBS?");
	if(ril_command_exec_singleline_for_result(thiz, cmd, "+CPBS:", &p_resp))
	{
		int record_count = 0;
		int ef_size = 0;
		int ignored = 0;

		at_line_scanf_int_int_int(p_resp->p_intermediates->line,
			&ignored, &ignored, &record_count);
		ef_size = record_count * EF_ADN_RECORD_SIZE;

		resp_data[0] = 0;
		resp_data[1] = 0;
		resp_data[2] = ef_size >> 8;
		resp_data[3] = ef_size & 0xFF;
		resp_data[4] = io_args->fileid >> 8;
		resp_data[5] = io_args->fileid & 0xFF;
		resp_data[6] = 4;
		resp_data[7] = 0;
		resp_data[8] = 0x11;
		resp_data[9] = 0xF0;
		resp_data[10] = 0x44;
		resp_data[11] = 0x01;
		resp_data[12] = 0x02;
		resp_data[13] = 0x01;
		resp_data[14] = EF_ADN_RECORD_SIZE;
		resp_data[15] = 0;
		
		PrintBuffer("ADN: ", (unsigned char*)resp_data, 16);
		io_resp->simResponse = hexToString((unsigned char*)resp_data, 16);
		io_resp->sw1 = 0x90;
		io_resp->sw2 = 0x00;
		at_response_free(p_resp);
		ret = 1;
	}

	return ret;
}

static int ef_dialling_numbers_read_record(RIL* thiz,
	RIL_SIM_IO_v5* io_args, RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;
	char cmd[32];
	ATResponse* p_resp = NULL;
	
	if(io_args->p2 == READ_RECORD_MODE_ABSOLUTE)
	{
		snprintf(cmd, 32, "AT+CPBS=\"SM\"");
		ril_command_exec_for_result(thiz, cmd);
		snprintf(cmd, 32, "AT^CPBR=%d", io_args->p1);
		if(ril_command_exec_singleline_for_result(thiz, cmd, "^CPBR:", &p_resp))
		{
			PbookInfo pb_info;
			char* text = NULL;
			unsigned char* efData = NULL;
			int efDataLen = 0;

			at_line_scanf_int_string_int_string_int(p_resp->p_intermediates->line,
				&pb_info.index, (char**)&pb_info.number, &pb_info.number_type, &text, &pb_info.coding);
			pb_info.number_len = strlen((char*)pb_info.number);
			if(pb_info.coding == 1)
			{
				int i = 0;

				pb_info.text = StringToHex((unsigned char*)text + 2, strlen(text) - 2);
				pb_info.text_len = strlen(text) / 2 - 1;
				for(i = 0; i < pb_info.text_len; i+=2)
				{
					ALOGD("%c,%c", pb_info.text[i], pb_info.text[i + 1]);
					if(pb_info.text[i] == 0 && pb_info.text[i + 1] == 0)
					{
						pb_info.text_len = i;
						break;
					}
				}
			}
			else
			{
				pb_info.text = (unsigned char*)strdup(text);
				pb_info.text_len = strlen(text);
			}
			ruim_pbook_encode(&pb_info, &efData, &efDataLen);

			io_resp->simResponse = hexToString(efData, efDataLen);
			io_resp->sw1 = 0x90;
			io_resp->sw2 = 0x00;
			free(pb_info.text);
			free(efData);
			at_response_free(p_resp);
			ret = 1;
		}
		else
		{
			io_resp->simResponse = calloc(1, EF_ADN_RECORD_SIZE * 2 + 1);
			memset(io_resp->simResponse, 'F', EF_ADN_RECORD_SIZE * 2);
			io_resp->sw1 = 0x90;
			io_resp->sw2 = 0x00;

			ret = 1;
		}
	}

	return ret;
}

static int ef_dialling_numbers_update_record(RIL* thiz,
	RIL_SIM_IO_v5* io_args, RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;
	char resp_data[16];
	char cmd[256];
	
	if(io_args->p2 == READ_RECORD_MODE_ABSOLUTE)
	{
		PbookInfo pb_info;
		char* text = NULL;
		unsigned char* efData = NULL;
		int efDataLen = 0;

		snprintf(cmd, 32, "AT+CPBS=\"SM\"");
		ril_command_exec_for_result(thiz, cmd);

		efData = StringToHex((unsigned char*)io_args->data, strlen(io_args->data));
		ruim_pbook_decode(efData, efDataLen, &pb_info);

		if(pb_info.coding == 1)
		{
			text = hexToString(pb_info.text, pb_info.text_len);
		}
		else
		{
			text = strdup((char*)pb_info.text);
		}
		snprintf(cmd, 256, "AT^CPBW=%d,%s,%d,%s,%d", io_args->p1, pb_info.number, 
			pb_info.number_type, text, pb_info.coding);
		if(ril_command_exec_for_result(thiz, cmd))
		{
			
			io_resp->sw1 = 0x90;
			io_resp->sw2 = 0x00;
			ret = 1;
		}

		free(pb_info.text);
		free(pb_info.number);
		free(efData);
		free(text);
	}

	return ret;
}

static int sms_get_response(RIL* thiz,
	RIL_SIM_IO_v5* io_args, RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;
	char resp_data[16];
	char cmd[32];
	ATResponse* p_resp = NULL;
	
	snprintf(cmd, 32, "AT+CPMS?");
	if(ril_command_exec_singleline_for_result(thiz, cmd, "+CPMS:", &p_resp))
	{
		int record_count = 0;
		int ef_size = 0;
		int ignored = 0;

		at_line_scanf_int_int_int(p_resp->p_intermediates->line,
			&ignored, &ignored, &record_count);
		ef_size = record_count * EF_SMS_RECORD_SIZE;

		resp_data[0] = 0;
		resp_data[1] = 0;
		resp_data[2] = ef_size >> 8;
		resp_data[3] = ef_size & 0xFF;
		resp_data[4] = io_args->fileid >> 8;
		resp_data[5] = io_args->fileid & 0xFF;
		resp_data[6] = 4;
		resp_data[7] = 0;
		resp_data[8] = 0x11;
		resp_data[9] = 0xF0;
		resp_data[10] = 0x44;
		resp_data[11] = 0x01;
		resp_data[12] = 0x02;
		resp_data[13] = 0x01;
		resp_data[14] = EF_SMS_RECORD_SIZE;
		resp_data[15] = 0;
	
		io_resp->simResponse = hexToString((unsigned char*)resp_data, 16);
		io_resp->sw1 = 0x90;
		io_resp->sw2 = 0x00;
		at_response_free(p_resp);
		ret = 1;
	}

	return ret;
}

static int sms_read_recrod(RIL* thiz,
	RIL_SIM_IO_v5* io_args, RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;

	if(io_args->p2 == READ_RECORD_MODE_ABSOLUTE)
	{
		int err = 0;
		char cmd[32];
		ATResponse* p_resp = NULL;

		snprintf(cmd, 32, "AT^HCMGR=%d", io_args->p1);
		err = ril_send_command_multiline(thiz, cmd, "", &p_resp);
		if(err == 0 && p_resp->success == 1)
		{
			unsigned char* pdu = NULL;
			unsigned char* efData = NULL;
			int efDataLen = 0;
			int status = 0;
			int ignored = 0;

			at_line_scanf_int_int_int(p_resp->p_intermediates->line,
					&ignored, &status, &ignored);
			pdu = StringToHex((unsigned char*)p_resp->p_intermediates->p_next->line, 
					strlen(p_resp->p_intermediates->p_next->line));
			ruim_sms_encode(status, pdu, strlen(p_resp->p_intermediates->p_next->line) / 2,
					&efData, &efDataLen);

			io_resp->simResponse = hexToString(efData, efDataLen);
			io_resp->sw1 = 0x90;
			io_resp->sw2 = 0x00;
			
			at_response_free(p_resp);
			free(pdu);
			free(efData);
			ret = 1;
		}
	}

	return ret;
}

static int ruim_ef_dialling_numbers_io(RIL* thiz, RIL_SIM_IO_v5* io_args, 
	RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;

	ALOGD("ruim_ef_dialling_numbers_io");
	switch(io_args->command)
	{
	case COMMAND_GET_RESPONSE:
		ret = ef_dialling_numbers_get_response(thiz, io_args, io_resp);
		break;

	case COMMAND_READ_RECORD:
		ret = ef_dialling_numbers_read_record(thiz, io_args, io_resp);
		break;

	case COMMAND_UPDATE_RECORD:
		//ret = ef_dialling_numbers_update_record(thiz, io_args, io_resp);
		break;

	default:
		break;
	}

	return ret;
}

static int ruim_ef_sms_io(RIL* thiz, RIL_SIM_IO_v5* io_args, 
	RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;
	
	ALOGD("ruim_ef_sms_io");
	switch(io_args->command)
	{
	case COMMAND_GET_RESPONSE:
		ret = sms_get_response(thiz, io_args, io_resp);
		break;

	case COMMAND_READ_RECORD:
		ret = sms_read_recrod(thiz, io_args, io_resp);
		break;

	default:
		break;
	}

	return ret;
}

static int ruim_SIM_IO(RIL* thiz, RIL_SIM_IO_v5* io_args, RIL_SIM_IO_Response* io_resp)
{
	int ret = 0;

	switch(io_args->fileid)
	{
	case EF_ADN:
//	case EF_FDN:
		ret = ruim_ef_dialling_numbers_io(thiz, io_args, io_resp);
		break;

	case EF_SMS:
		ret = ruim_ef_sms_io(thiz, io_args, io_resp);
		break;

	default:
		break;
	}

	return ret;
}

static void  requestSIM_IO(RIL* thiz, void *data, size_t datalen, RIL_Token t)
{
    RIL_SIM_IO_Response sr;
    RIL_SIM_IO_v5 *p_args;

    memset(&sr, 0, sizeof(sr));
    p_args = (RIL_SIM_IO_v5 *)data;

	if(ruim_SIM_IO(thiz, p_args, &sr))
	{
		ALOGD("requestSIM_IO: sw1=%d,dw2=%d,simResponse=%s\n", sr.sw1, sr.sw2, sr.simResponse);
    	RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &sr, sizeof(sr));
		free(sr.simResponse);
	}
    else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestEnterNetworkDepersonalization(RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	char cmd[64] = {0};
	const char* pin = ((const char**)data)[0];

	snprintf(cmd, 64, "AT+CLCK=\"PN\",0,%s", pin);
	if (ril_command_exec_for_result(thiz, cmd))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
	}

	return;
}

static void requestCdmaSubscription(RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	char* response[5];
	int err = 0;
    ATResponse* p_mdn_resp  = NULL;
	ATResponse* p_min_resp = NULL;
    ATResponse* p_sid_resp = NULL;
    ATResponse* p_prlv_resp = NULL;
    int success = 0;
	    
    do
    {
        if(!ril_command_exec_singleline_for_result(thiz, "AT+MDN", "", &p_mdn_resp))
	    {
            break;
        }
        response[0] = p_mdn_resp->p_intermediates->line;
		if(strcmp(response[0], "0000000000") == 0)
		{
			response[0] = NULL;
		}
		ALOGD("subscription: mdn=%s", response[0]);

	    if(!ril_command_exec_singleline_for_result(thiz, "AT+CMIN", "+CMIN:", &p_min_resp))
	    {
            break;
        }
		at_line_scanf_string(p_min_resp->p_intermediates->line, &response[3]);
		ALOGD("subscription: min=%s", response[3]);

        err = ril_send_command_multiline(thiz, "AT^SIDNID", "", &p_sid_resp);
        ALOGD("err=%d,p_sid_resp->success =%d", err, p_sid_resp->success);
        if(err == 0 && p_sid_resp->success == 1)
        {
            response[1] = p_sid_resp->p_intermediates->line + 4;
            response[2] = p_sid_resp->p_intermediates->p_next->line + 4;
            ALOGD("hsid=%s\n", response[1]);
            ALOGD("nid=%s\n", response[2]);
        }
        else
        {
            break;
        }

        if(!ril_command_exec_singleline_for_result(thiz, "AT+CPRL?", "+CPRL:", &p_prlv_resp))
        {
			if(!ril_command_exec_singleline_for_result(thiz, "AT+CPRL", "+CPRL:", &p_prlv_resp))
			{
            	break;
			}
        }
        at_line_scanf_string(p_prlv_resp->p_intermediates->line, &response[4]);
        success = 1;
    }while(0);

    if(success)
    {
        RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, response, sizeof(response));
    }
    else
    {
        RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
    }
    
    at_response_free(p_mdn_resp);
    at_response_free(p_min_resp);
    at_response_free(p_sid_resp);
    at_response_free(p_prlv_resp);
}

static void requestGetImsi(RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	ATResponse* p_response = NULL;

    if (ril_command_exec_singleline_for_result(thiz, "AT+CIMI", "+CIMI:", &p_response))
	{
		char* imsi = NULL;

		at_line_scanf_string(p_response->p_intermediates->line, &imsi);
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, imsi, sizeof(char *));
		at_response_free(p_response);
    } 
	else 
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
    }

	return;
}

static void requestEnterSimPin2 (RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	char	cmd[64] = {0};
	const char* pin2 = NULL;

	pin2 = ((const char**)data)[0];

	snprintf(cmd, 64, "AT+CPIN=\"%s\"", pin2);
	if (ril_command_exec_for_result(thiz, cmd))
	{
		 RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
	}

	return;
}

static void requestChangeSimPin2(RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	const char** pins = (const char**)data;
	char cmd[64] = {0};
	
	snprintf(cmd, 64, "AT+CPWD=\"P2\",\"%s\",\"%s\"", pins[0], pins[1]);
	if (ril_command_exec_for_result(thiz, cmd))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
	}

	return;
}

static void requestChangeSimPin(RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	const char** pins = (const char**)data;
	char cmd[64] = {0};
	
	snprintf(cmd, 64, "AT+CPWD=\"SC\",\"%s\",\"%s\"", pins[0], pins[1]);
	if (ril_command_exec_for_result(thiz, cmd))
	{
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
	}

	return;
}

static void requestGetSimPinRemainTimes(RIL* thiz, void*  data, size_t  datalen, RIL_Token t)
{
	ATResponse* p_resp = NULL;

	if(ril_command_exec_singleline_for_result(thiz, "AT^CPIN?", "^CPIN:", &p_resp))
	{
		int count[4] = {0};
		int ignored_int = 0;
		char* ignored_str = NULL;
		
		at_line_scanf_string_int_int_int_int_int(p_resp->p_intermediates->line,
			&ignored_str, &ignored_int, &count[2], &count[0],  &count[3],  &count[1]);
		RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, &count, sizeof(count));
		at_response_free(p_resp);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_GENERIC_FAILURE, NULL, 0);
	}

	return;
}

static void requestEnterSimPuk2(RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	char	cmd[64] = {0};
	const char** pin2s = NULL;

	pin2s = (const char**)data;

	snprintf(cmd, 64, "AT+CPIN=\"%s\",\"%s\"", pin2s[0], pin2s[1]);
	if (ril_command_exec_for_result(thiz, cmd))
	{
		 RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
	}

	return;
}

static void requestEnterSimPuk (RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	char	cmd[64] = {0};
	const char** pins = NULL;

	pins = (const char**)data;

	snprintf(cmd, 64, "AT+CPIN=\"%s\",\"%s\"", pins[0], pins[1]);
	if (ril_command_exec_for_result(thiz, cmd))
	{
		 RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
	}

	return;
}

static void requestEnterSimPin (RIL* thiz, void*  data, size_t  datalen, RIL_Token  t)
{
	char	cmd[64] = {0};
	const char* pin = NULL;

	pin = ((const char**)data)[0];

	snprintf(cmd, 64, "AT+CPIN=\"%s\"", pin);
	if (ril_command_exec_for_result(thiz, cmd))
	{
		 RIL_onRequestComplete(thiz, t, RIL_E_SUCCESS, NULL, 0);
	}
	else
	{
		RIL_onRequestComplete(thiz, t, RIL_E_PASSWORD_INCORRECT, NULL, 0);
	}

	return;
}

int RIL_getSIMStatus (RIL* thiz)
{
    ATResponse *p_response = NULL;
    int err = 0;
    int ret = 0;
    char *cpinLine = NULL;
    char *cpinResult = NULL;
	int State = 0;
	
	do{
		State = RIL_GetState (thiz);
	    if (State == RADIO_STATE_OFF || State == RADIO_STATE_UNAVAILABLE) {
    	    ret = RIL_SIM_NOT_READY;
			break;
    	}

	    err = ril_send_command_singleline(thiz, "AT+CPIN?", "+CPIN:", &p_response);
    	if (err != 0) {
	        ret = RIL_SIM_NOT_READY;
			break;
    	}
		
		err = at_get_cme_error(p_response);
		if(err != CME_SUCCESS)
		{
			if(err == CME_SIM_NOT_INSERTED)
			{
				ret = RIL_SIM_ABSENT;
			} else {
				ret = RIL_SIM_NOT_READY;
			}
			break;
		}

    	/* CPIN? has succeeded, now look at the result */
	    cpinLine = p_response->p_intermediates->line;
    	err = at_tok_start (&cpinLine);
	    if (err < 0) {
    	    ret = RIL_SIM_NOT_READY;
			break;
	    }

    	err = at_tok_nextstr(&cpinLine, &cpinResult);
	    if (err < 0) {
    	    ret = RIL_SIM_NOT_READY;
			break;
	    }

	    if (0 == strcmp (cpinResult, "SIM PIN")) {
    	    ret = RIL_SIM_PIN;
	    } else if (0 == strcmp (cpinResult, "SIM PUK")) {
			ATResponse* p_resp = NULL;
		
			ret = RIL_SIM_PUK;
			if(ril_command_exec_singleline_for_result(thiz, "AT^CPIN?", "^CPIN:", &p_resp))
			{
				int ignored = 0;
				int count = 0;
				char* ignored_str = NULL;
		
				at_line_scanf_string_int_int_int_int_int(p_resp->p_intermediates->line,
					&ignored_str, &ignored, &count, &ignored,  &ignored,  &ignored);
				at_response_free(p_resp);
				if(count == 0) 
				{
					ret = RIL_SIM_ABSENT;
				}
			}
    	} else if (0 == strcmp (cpinResult, "SIM PIN2")) {
        	ret = RIL_SIM_PIN2;
    	} else if (0 == strcmp(cpinResult, "SIM PUK2")){
			ret = RIL_SIM_PUK2;
		}else if (0 == strcmp (cpinResult, "READY"))  {
        	/* we're treating unsupported lock types as "sim absent" */
	        ret = RIL_SIM_READY;
	    }else {
			ret = RIL_SIM_ABSENT;
		}
	}while(0);

    at_response_free(p_response);
    return ret;
}


int RIL_initialize_sim (RIL* thiz)
{
	return 1;
}

int RIL_onUnsolicited_sim (RIL* thiz, const char* s)
{
	int ret = 0;

	return ret;
}

int RIL_onRequest_sim (RIL* thiz, int request, void *data, size_t datalen, RIL_Token t)
{
	switch (request)
	{
	case RIL_REQUEST_GET_SIM_STATUS:
		requestGetSimState(thiz, data, datalen, t);
		break;
	
	case RIL_REQUEST_ENTER_SIM_PIN:
		requestEnterSimPin(thiz, data, datalen, t);
		RIL_pollSIMState(thiz);
		break;

	case RIL_REQUEST_ENTER_SIM_PUK:
		requestEnterSimPuk(thiz, data, datalen, t);
		RIL_pollSIMState(thiz);
		break;

	case RIL_REQUEST_ENTER_SIM_PIN2:
		requestEnterSimPin2(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_ENTER_SIM_PUK2:
		requestEnterSimPuk2(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_GET_SIM_PIN_REMAIN_TIMES:
		requestGetSimPinRemainTimes(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_CHANGE_SIM_PIN:
		requestChangeSimPin(thiz, data, datalen, t);
		RIL_pollSIMState(thiz);
		break;

	case RIL_REQUEST_CHANGE_SIM_PIN2:
		requestChangeSimPin2(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_GET_IMSI:
		requestGetImsi(thiz, data, datalen, t);
		break;

	case RIL_REQUEST_SIM_IO:
		requestSIM_IO(thiz, data,datalen,t);
		break;

	/*TODO: */
	case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION:
		/*TODO: */
		//requestEnterNetworkDepersonalization(thiz, data, datalen, t);
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;
	
	case RIL_REQUEST_CDMA_SUBSCRIPTION:
		requestCdmaSubscription(thiz, data, datalen, t);
		break;

	//case RIL_REQUEST_CDMA_SET_SUBSCRIPTION:
	//	/*TODO: */
	//	RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
	//	break;

	default:
		RIL_onRequestComplete(thiz, t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
		break;

	}

	return 1;
}

